package com.powerbank.financecenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.powerbank.common.client.UserCenterClient;
import com.powerbank.common.dto.AccountDTO;
import com.powerbank.common.dto.TransactionRequest;
import com.powerbank.common.dto.UserDTO;
import com.powerbank.common.dto.WithdrawalRequest;
import com.powerbank.common.event.EventPublisher;
import com.powerbank.common.event.TransactionCompletedEvent;
import com.powerbank.common.event.WithdrawalProcessedEvent;
import com.powerbank.common.exception.BusinessException;
import com.powerbank.common.result.Result;
import com.powerbank.common.utils.TransactionNoGenerator;
import com.powerbank.financecenter.entity.TransactionRecord;
import com.powerbank.financecenter.entity.UserAccount;
import com.powerbank.financecenter.entity.WithdrawalRecord;
import com.powerbank.financecenter.mapper.TransactionRecordMapper;
import com.powerbank.financecenter.mapper.UserAccountMapper;
import com.powerbank.financecenter.mapper.WithdrawalRecordMapper;
import com.powerbank.financecenter.service.UserAccountService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户账户服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {

    private final UserAccountMapper userAccountMapper;
    private final TransactionRecordMapper transactionRecordMapper;
    private final WithdrawalRecordMapper withdrawalRecordMapper;
    private final UserCenterClient userCenterClient;
    private final EventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<AccountDTO> createAccount(Long userId, String accountType) {
        // 验证用户是否存在
        Result<UserDTO> userResult = userCenterClient.getUserById(userId);
        if (!userResult.isSuccess() || userResult.getData() == null) {
            return Result.fail("用户不存在");
        }

        // 检查账户是否已存在
        UserAccount existingAccount = userAccountMapper.findByUserIdAndType(userId, accountType);
        if (existingAccount != null) {
            AccountDTO accountDTO = convertToDTO(existingAccount);
            return Result.success(accountDTO);
        }

        // 创建新账户
        UserAccount account = new UserAccount();
        account.setUserId(userId);
        account.setAccountType(accountType);
        account.setBalance(BigDecimal.ZERO);
        account.setFrozenAmount(BigDecimal.ZERO);
        account.setTotalRecharge(BigDecimal.ZERO);
        account.setTotalConsume(BigDecimal.ZERO);
        account.setTotalRefund(BigDecimal.ZERO);
        account.setStatus("ACTIVE");

        save(account);

        AccountDTO accountDTO = convertToDTO(account);
        return Result.success(accountDTO);
    }

    @Override
    public Result<AccountDTO> getAccountByUserIdAndType(Long userId, String accountType) {
        UserAccount account = userAccountMapper.findByUserIdAndType(userId, accountType);
        if (account == null) {
            return Result.fail("账户不存在");
        }

        AccountDTO accountDTO = convertToDTO(account);
        return Result.success(accountDTO);
    }

    @Override
    public Result<List<AccountDTO>> getUserAccounts(Long userId) {
        LambdaQueryWrapper<UserAccount> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserAccount::getUserId, userId)
               .eq(UserAccount::getDeleted, 0);

        List<UserAccount> accounts = list(wrapper);
        List<AccountDTO> accountDTOs = accounts.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        return Result.success(accountDTOs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> recharge(TransactionRequest request) {
        UserAccount account = userAccountMapper.findByUserIdAndType(request.getUserId(), request.getAccountType());
        if (account == null) {
            return Result.fail("账户不存在");
        }

        if (!"ACTIVE".equals(account.getStatus())) {
            return Result.fail("账户状态异常");
        }

        // 生成交易号
        String transactionNo = TransactionNoGenerator.generate("RECHARGE");

        // 记录交易前余额
        BigDecimal balanceBefore = account.getBalance();

        // 增加账户余额
        int updated = userAccountMapper.addBalance(account.getId(), request.getAmount());
        if (updated == 0) {
            return Result.fail("充值失败");
        }

        // 刷新账户信息
        account = getById(account.getId());

        // 记录交易
        TransactionRecord transaction = new TransactionRecord();
        transaction.setTransactionNo(transactionNo);
        transaction.setUserId(request.getUserId());
        transaction.setAccountId(account.getId());
        transaction.setTransactionType("RECHARGE");
        transaction.setDirection("IN");
        transaction.setAmount(request.getAmount());
        transaction.setBalanceBefore(balanceBefore);
        transaction.setBalanceAfter(account.getBalance());
        transaction.setStatus("SUCCESS");
        transaction.setOrderNo(request.getOrderNo());
        transaction.setPaymentNo(request.getPaymentNo());
        transaction.setPaymentMethod(request.getPaymentMethod());
        transaction.setDescription(request.getDescription());
        transactionRecordMapper.insert(transaction);

        // 发送交易完成事件
        TransactionCompletedEvent event = new TransactionCompletedEvent(
                transactionNo, request.getUserId(), request.getAmount(), "RECHARGE");
        eventPublisher.publishEvent(event);

        log.info("用户充值成功: userId={}, amount={}, transactionNo={}", request.getUserId(), request.getAmount(), transactionNo);
        return Result.success(transactionNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> consume(TransactionRequest request) {
        UserAccount account = userAccountMapper.findByUserIdAndType(request.getUserId(), request.getAccountType());
        if (account == null) {
            return Result.fail("账户不存在");
        }

        if (!"ACTIVE".equals(account.getStatus())) {
            return Result.fail("账户状态异常");
        }

        // 检查余额是否充足
        if (account.getBalance().compareTo(request.getAmount()) < 0) {
            return Result.fail("账户余额不足");
        }

        // 生成交易号
        String transactionNo = TransactionNoGenerator.generate("CONSUME");

        // 记录交易前余额
        BigDecimal balanceBefore = account.getBalance();

        // 扣减账户余额
        int updated = userAccountMapper.deductBalance(account.getId(), request.getAmount());
        if (updated == 0) {
            return Result.fail("消费失败");
        }

        // 刷新账户信息
        account = getById(account.getId());

        // 记录交易
        TransactionRecord transaction = new TransactionRecord();
        transaction.setTransactionNo(transactionNo);
        transaction.setUserId(request.getUserId());
        transaction.setAccountId(account.getId());
        transaction.setTransactionType("CONSUME");
        transaction.setDirection("OUT");
        transaction.setAmount(request.getAmount());
        transaction.setBalanceBefore(balanceBefore);
        transaction.setBalanceAfter(account.getBalance());
        transaction.setStatus("SUCCESS");
        transaction.setOrderNo(request.getOrderNo());
        transaction.setPaymentNo(request.getPaymentNo());
        transaction.setPaymentMethod(request.getPaymentMethod());
        transaction.setDescription(request.getDescription());
        transactionRecordMapper.insert(transaction);

        // 发送交易完成事件
        TransactionCompletedEvent event = new TransactionCompletedEvent(
                transactionNo, request.getUserId(), request.getAmount(), "CONSUME");
        eventPublisher.publishEvent(event);

        log.info("用户消费成功: userId={}, amount={}, transactionNo={}", request.getUserId(), request.getAmount(), transactionNo);
        return Result.success(transactionNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> refund(TransactionRequest request) {
        UserAccount account = userAccountMapper.findByUserIdAndType(request.getUserId(), request.getAccountType());
        if (account == null) {
            return Result.fail("账户不存在");
        }

        if (!"ACTIVE".equals(account.getStatus())) {
            return Result.fail("账户状态异常");
        }

        // 生成交易号
        String transactionNo = TransactionNoGenerator.generate("REFUND");

        // 记录交易前余额
        BigDecimal balanceBefore = account.getBalance();

        // 增加账户余额（退款）
        int updated = userAccountMapper.addBalance(account.getId(), request.getAmount());
        if (updated == 0) {
            return Result.fail("退款失败");
        }

        // 刷新账户信息
        account = getById(account.getId());

        // 记录交易
        TransactionRecord transaction = new TransactionRecord();
        transaction.setTransactionNo(transactionNo);
        transaction.setUserId(request.getUserId());
        transaction.setAccountId(account.getId());
        transaction.setTransactionType("REFUND");
        transaction.setDirection("IN");
        transaction.setAmount(request.getAmount());
        transaction.setBalanceBefore(balanceBefore);
        transaction.setBalanceAfter(account.getBalance());
        transaction.setStatus("SUCCESS");
        transaction.setOrderNo(request.getOrderNo());
        transaction.setPaymentNo(request.getPaymentNo());
        transaction.setPaymentMethod(request.getPaymentMethod());
        transaction.setDescription(request.getDescription());
        transactionRecordMapper.insert(transaction);

        // 发送交易完成事件
        TransactionCompletedEvent event = new TransactionCompletedEvent(
                transactionNo, request.getUserId(), request.getAmount(), "REFUND");
        eventPublisher.publishEvent(event);

        log.info("用户退款成功: userId={}, amount={}, transactionNo={}", request.getUserId(), request.getAmount(), transactionNo);
        return Result.success(transactionNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> freezeAmount(Long accountId, BigDecimal amount) {
        UserAccount account = getById(accountId);
        if (account == null) {
            return Result.fail("账户不存在");
        }

        if (!"ACTIVE".equals(account.getStatus())) {
            return Result.fail("账户状态异常");
        }

        // 检查余额是否充足
        if (account.getBalance().compareTo(amount) < 0) {
            return Result.fail("账户余额不足");
        }

        // 冻结金额
        int updated = userAccountMapper.freezeAmount(accountId, amount);
        if (updated == 0) {
            return Result.fail("冻结金额失败");
        }

        log.info("账户金额冻结成功: accountId={}, amount={}", accountId, amount);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> unfreezeAmount(Long accountId, BigDecimal amount) {
        UserAccount account = getById(accountId);
        if (account == null) {
            return Result.fail("账户不存在");
        }

        // 解冻金额
        int updated = userAccountMapper.unfreezeAmount(accountId, amount);
        if (updated == 0) {
            return Result.fail("解冻金额失败");
        }

        log.info("账户金额解冻成功: accountId={}, amount={}", accountId, amount);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> applyWithdrawal(WithdrawalRequest request) {
        UserAccount account = userAccountMapper.findByUserIdAndType(request.getUserId(), "WALLET");
        if (account == null) {
            return Result.fail("账户不存在");
        }

        if (!"ACTIVE".equals(account.getStatus())) {
            return Result.fail("账户状态异常");
        }

        // 检查余额是否充足
        if (account.getBalance().compareTo(request.getAmount()) < 0) {
            return Result.fail("账户余额不足");
        }

        // 生成提现单号
        String withdrawalNo = TransactionNoGenerator.generate("WITHDRAW");

        // 冻结提现金额
        Result<Void> freezeResult = freezeAmount(account.getId(), request.getAmount());
        if (!freezeResult.isSuccess()) {
            return Result.fail("冻结金额失败");
        }

        // 记录提现申请
        WithdrawalRecord withdrawal = new WithdrawalRecord();
        withdrawal.setWithdrawalNo(withdrawalNo);
        withdrawal.setUserId(request.getUserId());
        withdrawal.setAmount(request.getAmount());
        withdrawal.setActualAmount(request.getAmount().subtract(BigDecimal.valueOf(2.00))); // 扣除2元手续费
        withdrawal.setFee(BigDecimal.valueOf(2.00));
        withdrawal.setWithdrawalMethod(request.getWithdrawalMethod());
        withdrawal.setAccountInfo(request.getAccountInfo());
        withdrawal.setStatus("PENDING");
        withdrawalRecordMapper.insert(withdrawal);

        log.info("提现申请成功: userId={}, amount={}, withdrawalNo={}", request.getUserId(), request.getAmount(), withdrawalNo);
        return Result.success(withdrawalNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> processWithdrawal(String withdrawalNo, String status, String remark) {
        WithdrawalRecord withdrawal = withdrawalRecordMapper.findByWithdrawalNo(withdrawalNo);
        if (withdrawal == null) {
            return Result.fail("提现记录不存在");
        }

        if (!"PENDING".equals(withdrawal.getStatus())) {
            return Result.fail("提现状态不正确");
        }

        UserAccount account = getById(withdrawal.getAccountId());
        if (account == null) {
            return Result.fail("账户不存在");
        }

        if ("APPROVED".equals(status)) {
            // 更新提现状态为处理中
            withdrawal.setStatus("PROCESSING");
            withdrawal.setProcessTime(LocalDateTime.now());
            withdrawal.setRemark(remark);
            withdrawalRecordMapper.updateById(withdrawal);
        } else if ("REJECTED".equals(status)) {
            // 拒绝提现，解冻金额
            Result<Void> unfreezeResult = unfreezeAmount(account.getId(), withdrawal.getAmount());
            if (!unfreezeResult.isSuccess()) {
                throw new BusinessException("解冻金额失败");
            }

            // 更新提现状态为已拒绝
            withdrawal.setStatus("REJECTED");
            withdrawal.setAuditTime(LocalDateTime.now());
            withdrawal.setAuditRemark(remark);
            withdrawalRecordMapper.updateById(withdrawal);
        } else if ("SUCCESS".equals(status)) {
            // 提现成功，扣减冻结金额
            // 更新提现状态为成功
            withdrawal.setStatus("SUCCESS");
            withdrawal.setCompleteTime(LocalDateTime.now());
            withdrawal.setRemark(remark);
            withdrawalRecordMapper.updateById(withdrawal);

            // 发送提现处理事件
            WithdrawalProcessedEvent event = new WithdrawalProcessedEvent(
                    withdrawalNo, withdrawal.getUserId(), withdrawal.getAmount(), "SUCCESS");
            eventPublisher.publishEvent(event);
        } else if ("FAILED".equals(status)) {
            // 提现失败，解冻金额
            Result<Void> unfreezeResult = unfreezeAmount(account.getId(), withdrawal.getAmount());
            if (!unfreezeResult.isSuccess()) {
                throw new BusinessException("解冻金额失败");
            }

            // 更新提现状态为失败
            withdrawal.setStatus("FAILED");
            withdrawal.setCompleteTime(LocalDateTime.now());
            withdrawal.setFailReason(remark);
            withdrawalRecordMapper.updateById(withdrawal);
        }

        log.info("提现处理完成: withdrawalNo={}, status={}", withdrawalNo, status);
        return Result.success();
    }

    @Override
    public Result<BigDecimal> getAccountBalance(Long accountId) {
        UserAccount account = getById(accountId);
        if (account == null) {
            return Result.fail("账户不存在");
        }

        return Result.success(account.getBalance());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateAccountStatus(Long accountId, String status) {
        UserAccount account = getById(accountId);
        if (account == null) {
            return Result.fail("账户不存在");
        }

        int updated = userAccountMapper.updateAccountStatus(accountId, status);
        if (updated == 0) {
            return Result.fail("更新账户状态失败");
        }

        log.info("账户状态更新成功: accountId={}, status={}", accountId, status);
        return Result.success();
    }

    @Override
    public Result<Object> getAccountStatistics() {
        Map<String, Object> statistics = new HashMap<>();

        // 统计账户总数
        LambdaQueryWrapper<UserAccount> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserAccount::getDeleted, 0);
        long totalAccounts = count(wrapper);
        statistics.put("totalAccounts", totalAccounts);

        // 统计各状态账户数量
        wrapper = new LambdaQueryWrapper<>();
        wrapper.select(UserAccount::getStatus)
               .eq(UserAccount::getDeleted, 0)
               .groupBy(UserAccount::getStatus);
        List<UserAccount> accounts = list(wrapper);
        Map<String, Long> statusCount = accounts.stream()
                .collect(Collectors.groupingBy(UserAccount::getStatus, Collectors.counting()));
        statistics.put("statusCount", statusCount);

        return Result.success(statistics);
    }

    private AccountDTO convertToDTO(UserAccount account) {
        AccountDTO dto = new AccountDTO();
        BeanUtils.copyProperties(account, dto);
        return dto;
    }
}